﻿/*
 * This file is part of CommunitySettlers.
 *
 * CommunitySettlers is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * CommunitySettlers is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with CommunitySettlers.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * Author: Christoph Husse
 * 
 * Also checkout our homepage: http://communitysettlers.codeplex.com/
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace SettlersEngine.Exported
{
    public class MarketResourceStack
    {
        public Resource Type { get { return Query.ResourceType; } }
        /// <summary>
        /// A market stack can't be removed immediately if it is not empty or there are settlers
        /// carrying resources to it.
        /// </summary>
        public Boolean IsEnabled { get { return Query.IsEnabled; } set { Query.IsEnabled = value; } }
        internal IResourceObject Query { get; set; }
    }

    public class MarketExtension : BuildingListener
    {
        private InternalBinding<MarketResourceStack> m_PendingTransport = new InternalBinding<MarketResourceStack>();
        private IResourceObject[] m_Queries;

        public int MaxConcurrency { get; private set; }
        public BindingList<MarketResourceStack> PendingTransport { get { return m_PendingTransport; } }

        internal MarketExtension(IBuildableObject inBuildable)
            : base(inBuildable)
        {
            if(inBuildable.Config.BuiltinType != BuildingType.Market)
                throw new ArgumentException();

            m_Queries = (from e in inBuildable.Queries where (e.ResourceType == Resource.Max) select e).ToArray();
            MaxConcurrency = m_Queries.Length;

            foreach (var query in m_Queries)
            {
                query.OnCountChanged += Query_OnCountChanged;
            }
        }

        void Query_OnCountChanged(IResourceObject inSender, int inOldValue, int inNewValue)
        {
            if (inSender.IsEnabled)
            {
                /*
                 * As long as the query is enabled, all things are fine...
                 */

                return;
            }

            if (inSender.Count > 0)
            {
                /*
                 * There are still resources on this stack, so we can't remove it now.
                 */

                return;
            }

            // remove stack
            foreach (var stack in m_PendingTransport)
            {
                if (stack.Query == inSender)
                {
                    m_PendingTransport.RemoveInternal(stack);

                    break;
                }
            }

            // reset query
            inSender.ResourceType = Resource.Max;
        }

        public void AddResource(Resource inResource)
        {
            if (inResource == Resource.Max)
                throw new ArgumentException();

            if (m_PendingTransport.Count >= MaxConcurrency)
                return;

            // find free query
            IResourceObject freeQuery = null;

            foreach (var query in m_Queries)
            {
                if (m_PendingTransport.Count(e => e.Query == query) == 0)
                {
                    freeQuery = query;
                    break;
                }
            }

            if (freeQuery == null)
                throw new ApplicationException("No free resource query available.");

            freeQuery.ResourceType = inResource;
            freeQuery.IsEnabled = true;

            m_PendingTransport.AddInternal(new MarketResourceStack() { Query = freeQuery });
        }
    }
}
